/*
 * sht21.c
 *
 *  Created on: 08.08.2011
 *      Author: margel
 */

#include <stdint.h>
#include <stdio.h>

#include "appdefs.h"
#include "platform_config.h"
#include "stm32f10x.h"
#include "hw_config.h"
#include "lib_dbg.h"
#include "sht21.h"
#include "I2C_HAL.h"


uint8_t SHT21_CheckCrc( uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum );
uint8_t CRC8( uint8_t *pcBlock, uint8_t len );

void SHT21_Init()
{
	/*
	 * Configure pins and I2C
	 */
	//RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C1, ENABLE );

GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = SHT21_GPIO_SCL_PIN | SHT21_GPIO_SDA_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init( SHT21_GPIO_PORT, &GPIO_InitStructure );

	I2c_Init();

//I2C_InitTypeDef I2C_InitStructure;
//	I2C_InitStructure.I2C_ClockSpeed = SHT21_SPEED;
//	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
//	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
//	I2C_InitStructure.I2C_OwnAddress1 = SHT21_ADDRESS;
//	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
//	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
//
//	I2C_Init( I2C1, &I2C_InitStructure );
//	I2C_Cmd( I2C1, ENABLE );
}

//===========================================================================
uint8_t SHT21_SoftReset()
{
	  uint8_t  error=0;           //error variable

	  I2c_StartCondition();
	  error |= I2c_WriteByte (I2C_ADR_W); // I2C Adr
	  error |= I2c_WriteByte (SOFT_RESET);                            // Command
	  I2c_StopCondition();

	  DelayMicroSeconds(1000); // wait till sensor has restarted

	  return error;
}

uint8_t SHT21_WriteUserRegister( uint8_t *value )
{
uint8_t error = 0;
	I2c_StartCondition();
	error |= I2c_WriteByte (I2C_ADR_W);
	error |= I2c_WriteByte (USER_REG_W);
	error |= I2c_WriteByte (*value);
	I2c_StopCondition();
	return error;
}

//===========================================================================
uint8_t SHT21_MeasureHM(etSHT2xMeasureType eSHT2xMeasureType, uint16_t *pMeasurand)
//===========================================================================
{
  uint8_t  checksum;   //checksum
  uint8_t  data[2];    //data array for checksum verification
  uint8_t  error=0;    //error variable
  uint16_t i;          //counting variable

  //-- write I2C sensor address and command --
  I2c_StartCondition();
  error |= I2c_WriteByte (I2C_ADR_W); // I2C Adr
  switch(eSHT2xMeasureType)
  { case HUMIDITY: error |= I2c_WriteByte (TRIG_RH_MEASUREMENT_HM); break;
    case TEMP    : error |= I2c_WriteByte (TRIG_T_MEASUREMENT_HM);  break;
  }
  //-- wait until hold master is released --
  I2c_StartCondition();
  error |= I2c_WriteByte (I2C_ADR_R);
  SCL_HIGH();                     // set SCL I/O port as input
  for(i=0; i<1000; i++)         // wait until master hold is released or
  { DelayMicroSeconds(1000);    // a timeout (~1s) is reached
    if ( GPIO_ReadInputDataBit( SHT21_GPIO_PORT, SHT21_GPIO_SCL_PIN ) == Bit_SET ) break;
  }
  //-- check for timeout --
  if( GPIO_ReadInputDataBit( SHT21_GPIO_PORT, SHT21_GPIO_SCL_PIN ) == Bit_RESET ) error |= TIME_OUT_ERROR;

  //-- read two data bytes and one checksum byte --
  data[0] = I2c_ReadByte(ACK);
  data[1] = I2c_ReadByte(ACK);
  checksum=I2c_ReadByte(NO_ACK);

  *pMeasurand = 0;
  *pMeasurand |= ( data[0] << 8 );
  *pMeasurand |= data[1];

  //-- verify checksum --
  error |= SHT21_CheckCrc (data,2,checksum);
  I2c_StopCondition();
  return error;
}



uint8_t SHT21_ReadUserRegister( uint8_t *value )
{
uint8_t error = 0;
uint8_t checksum;   //variable for checksum byte

	I2c_StartCondition();
	error |= I2c_WriteByte (I2C_ADR_W);
	error |= I2c_WriteByte (USER_REG_R);
	I2c_StartCondition();
	error |= I2c_WriteByte (I2C_ADR_R);
	*value = I2c_ReadByte(ACK);
	checksum=I2c_ReadByte(NO_ACK);
	error |= SHT21_CheckCrc (value,1,checksum);
	I2c_StopCondition();
	return error;
}

uint8_t SHT21_GetSerialNumber( uint8_t u8SerialNumber[] )
{
uint8_t  error=0;                          //error variable
uint8_t  checksum = 0;

	//Read from memory location 1
	I2c_StartCondition();
	error |= I2c_WriteByte (I2C_ADR_W);    //I2C address
	error |= I2c_WriteByte (0xFA);         //Command for readout on-chip memory
	error |= I2c_WriteByte (0x0F);         //on-chip memory address
	I2c_StartCondition();
	error |= I2c_WriteByte (I2C_ADR_R);    //I2C address
	u8SerialNumber[5] = I2c_ReadByte(ACK); //Read SNB_3
	checksum = I2c_ReadByte(ACK);                     //Read CRC SNB_3 (CRC is not analyzed)
	error |= SHT21_CheckCrc( &u8SerialNumber[5], 1, checksum );
	u8SerialNumber[4] = I2c_ReadByte(ACK); //Read SNB_2
	checksum = I2c_ReadByte(ACK);                     //Read CRC SNB_2 (CRC is not analyzed)
	error |= SHT21_CheckCrc( &u8SerialNumber[4], 1, checksum );
	u8SerialNumber[3] = I2c_ReadByte(ACK); //Read SNB_1
	checksum = I2c_ReadByte(ACK);                     //Read CRC SNB_1 (CRC is not analyzed)
	error |= SHT21_CheckCrc( &u8SerialNumber[3], 1, checksum );
	u8SerialNumber[2] = I2c_ReadByte(ACK); //Read SNB_0
	checksum = I2c_ReadByte(NO_ACK);                  //Read CRC SNB_0 (CRC is not analyzed)
	error |= SHT21_CheckCrc( &u8SerialNumber[2], 1, checksum );
	I2c_StopCondition();

	//Read from memory location 2
	I2c_StartCondition();
	error |= I2c_WriteByte (I2C_ADR_W);    //I2C address
	error |= I2c_WriteByte (0xFC);         //Command for readout on-chip memory
	error |= I2c_WriteByte (0xC9);         //on-chip memory address
	I2c_StartCondition();
	error |= I2c_WriteByte (I2C_ADR_R);    //I2C address
	u8SerialNumber[1] = I2c_ReadByte(ACK); //Read SNC_1
	u8SerialNumber[0] = I2c_ReadByte(ACK); //Read SNC_0
	I2c_ReadByte(ACK);                     //Read CRC SNC0/1 (CRC is not analyzed)
	u8SerialNumber[7] = I2c_ReadByte(ACK); //Read SNA_1
	u8SerialNumber[6] = I2c_ReadByte(ACK); //Read SNA_0
	I2c_ReadByte(NO_ACK);                  //Read CRC SNA0/1 (CRC is not analyzed)
	I2c_StopCondition();

return error;
}

/*
  Name  : CRC-8
  Poly  : 0x31    x^8 + x^5 + x^4 + 1
  Init  : 0xFF
  Revert: false
  XorOut: 0x00
  Check : 0xF7 ("123456789")
  MaxLen: 15 байт(127 бит) - обнаружение
    одинарных, двойных, тройных и всех нечетных ошибок
*/
uint8_t CRC8( uint8_t *pcBlock, uint8_t len )
{
    unsigned char crc = 0xFF;
    unsigned int i;

    while (len--)
    {
        crc ^= *pcBlock++;

        for (i = 0; i < 8; i++)
            crc = crc & 0x80 ? (crc << 1) ^ 0x31 : crc << 1;
    }

    return crc;
}


//==============================================================================
uint8_t SHT21_CheckCrc( uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum )
//==============================================================================
{
uint8_t crc = 0;
uint8_t byteCtr;
	//calculates 8-Bit checksum with given polynomial
	for( byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr )
	{
		crc ^= ( data[byteCtr] );
    	for( uint8_t bit = 8; bit > 0; --bit )
    	{
    		if (crc & 0x80)
    			crc = (crc << 1) ^0x31;
    		else
    			crc = (crc << 1);
    	}
	}
	if( crc != checksum )
		return 2;
	else
		return 0;
}
